home *** CD-ROM | disk | FTP | other *** search
- /* This program is sort of a lava-lamp for your computer. It requires
- VGA equipment or anything else that is compatible with mode 13h of
- the VGA (320x200x256 mode). To run the program, execute the command
-
- ooze
-
- The first time this is run, it will generate a random, amorphous
- image on the screen and will store this image into the file ooze.ooz.
- The image on the screen will then begin to "ooze" all over the
- screen. To change the direction of oozing, press a key (like the
- space bar). To stop the program and return to DOS, press the Escape
- key.
-
- The next time ooze is run, it will read the file ooze.ooz and
- proceede directly to ooze the image stored there. Ooze.ooz is mearly
- the default filename. Any other filename may be specified on the
- command line. If, for instance, the command
-
- ooze image1.ooz
-
- is issued, the file image1.ooz will be read from disk (if it is
- present) and the image from this file will be oozed. If image1.ooze
- is not found, it will be created in the same manner as ooze.ooz was
- created above. But the image created will be different for every new
- ooze image file created. You could build a whole library of differnet
- ooze files!
-
- ---------------------- For Programmers Only -------------------------
-
- This program was translated to Turbo C from Turbo Pascal. The
- original TP code was written and copyrighted (1988) by Bret Bulvey
- [71330,3567] and can be found in various places as PLASMA.ARC (or
- .ZIP depending on where you get it). The translation to TC was done
- by me (Jeff Clough [71330,2227]) and includes improvements and
- enhancements over the TP code. These include the elimination of
- flicker, the use of secondary as well as primary colors in the color
- palette, the use of 252 colors instead of only the 191 colors used in
- PLASMA, the ability to reverse the direction in which the colors move
- on the screen while the program is executing, and being able to
- specify the name of the image file to use on the command line. Also,
- as a side-effect of the process by which flicker is avoided, OOZE
- should run at the same speed on all VGA equipment regardless of the
- speed of the computer. The only unique part of the original code
- presented here (aside from a few variable and type names) is the
- algorithm for generating the amorphous images. The algorithm has been
- modified (simplified, actually) so that it includes no floating
- point. The original algorithm employed the use of Manhattan distances
- to determine how far apart two pixels were. The code presented here
- employes its own square root function (using integer bisection) and
- uses this to take advantage of a little trick Pathagorus demonstrated
- a while back. It is hoped that this new method for computing
- distances will produce more rounded edges in the generated images.
- Also, there was provision in the original code for adjusting the
- "roughness of the image" at compile time. This has been removed
- (since it involved a floating point operation).
-
- To eliminate the flicker, it was necessary to implement parts of the
- program in assembly language. The code that follows is, therefore, a
- hybrid of Turbo C and Assembly. Turbo C 2.0 and TASM were used to
- compile/assemble this program. To recompile, do
-
- tcc -B -mc ooze
-
- This will cause TC to "compile" to assembly source code and then
- invoke TASM on that code. The -mc switch may optionally be changed to
- -ml or -mh for the large or huge memory models, but may not be
- changed to -mt, -ms, or -mm because the tiny, small, and medium
- memory models all use near data segments. The far data segments used
- by the other memory models are necessary because this program uses
- the fread and fwrite functions to read from and write to the video
- memory directly.
-
- If the identifier "dotest" is defined during compilation, a test
- pattern will be generated instead of the more usual amorphous images
- when the program is run. This test code was used during debugging to
- ensure that all colors were being represented on the screen. If you
- change any part of this source code, you may want to use this test
- pattern to verify that your changes meet your expectations of them.
- To tell the compiler to generate the test code, include the -Ddotest
- command line switch when you compile as follows:
-
- tcc -B -mc -Ddotest ooze
-
- When ooze.exe is run, the test pattern will be generated and stored
- into whatever file is passed to it on the command line or to ooze.ooz
- by default. Don't forget to recompile without the -Ddotest switch so
- that the program will once again generate amorphous images.
- */
-
- #if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__)
- #error COMPILE WITH LARGE DATA MODEL.
- #endif
-
- #include <bios.h>
- #include <dos.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #define VERSION "1.1"
-
- typedef struct
- {unsigned char r,g,b;
- } colortype;
-
- colortype p[256];
-
- int direction=0; /* controls the direction of palette rotation */
-
- void adjust(int x1,int y1,int x,int y,int x2,int y2);
- int getpixel(int x,int y);
- void putpixel(int x,int y,int c);
- void rotatepalette(colortype p[]);
- void setvgapalette(void *buffer,int first,int length);
- void subdivide(int x1,int y1,int x2,int y2);
- unsigned sqrt(long n);
- void test(void);
- void usage(void);
-
- int main(int argc,char *argv[])
- {FILE *file;
- char filename[129];
- union REGS reg;
- unsigned char r,g,b;
- int i, /* holds the number of the current palette register */
- key, /* holds the scancode of the last key pressed */
- newooze; /* TRUE if a new .OOZ file is to be created */
-
- newooze=0;
- if (argc>2)
- {usage();
- return 1;
- }
- if (argc>1)
- {if (stricmp(argv[1],"?")==0 ||
- stricmp(argv[1],"-H")==0 ||
- stricmp(argv[1],"/H")==0)
- {usage();
- return 1;
- }
- strcpy(filename,argv[1]);
- }
- else
- strcpy(filename,"ooze.ooz");
- file=fopen(filename,"rb");
- if (!file)
- {file=fopen(filename,"w+b");
- newooze=1;
- }
- if (!file)
- {printf("%s cannot be found or created.\n\n",filename);
- usage();
- return 2;
- }
-
- /* initialize palette register array */
- r=53;
- g=11;
- b=53;
- for(i=1;i<=42;i++) /* from magenta to red */
- {p[i].r=r;
- p[i].g=g;
- p[i].b=b--;
- }
- for(;i<=84;i++) /* from red to yellow */
- {p[i].r=r;
- p[i].g=++g;
- p[i].b=b;
- }
- for(;i<=126;i++) /* from yellow to green */
- {p[i].r=r--;
- p[i].g=g;
- p[i].b=b;
- }
- for(;i<=168;i++) /* from green to cyan */
- {p[i].r=r;
- p[i].g=g;
- p[i].b=++b;
- }
- for(;i<=210;i++) /* from cyan to blue */
- {p[i].r=r;
- p[i].g=g--;
- p[i].b=b;
- }
- for(;i<=252;i++) /* from blue to magenta */
- {p[i].r=++r;
- p[i].g=g;
- p[i].b=b;
- }
-
- /* put VGA into mode 0x13 (320x200x256) */
- reg.x.ax=0x13;
- int86(0x10,®,®);
-
- setvgapalette(p,0,128);
- setvgapalette(&p[128],128,128);
-
- if (newooze)
- {
- #if defined(dotest)
- test();
- #else
- srand(peek(0x40,0x6c));
- putpixel(0,0,random(252)+1);
- putpixel(319,0,random(252)+1);
- putpixel(319,199,random(252)+1);
- putpixel(0,199,random(252)+1);
- subdivide(0,0,319,199);
- #endif
- fwrite(MK_FP(0xa000,0),1,0xfa00,file);
- }
- else
- fread(MK_FP(0xa000,0),1,0xfa00,file);
- fclose(file);
-
- /* rotate the palette until the [Esc] key is pressed */
- do
- {rotatepalette(p);
- if (bioskey(1))
- {key=bioskey(0)>>8;
- direction=1-direction;
- }
- }
- while(key!=1);
-
- /* put VGA into mode 3 (color text mode (80x25)) */
- reg.x.ax=3;
- int86(0x10,®,®);
-
- return 0;
- } /* end of int main(argc,argv[]) */
-
- void adjust(int x1,int y1,int x,int y,int x2,int y2)
- {int c,d;
- long horz,vert;
- if (getpixel(x,y))
- return;
- horz=(long)(x2-x1);
- vert=(long)(y2-y1);
- d=sqrt(horz*horz+vert*vert);
- if (random(2))
- c=((getpixel(x1,y1)+getpixel(x2,y2))/2-random(d)) % 252;
- else
- c=((getpixel(x1,y1)+getpixel(x2,y2))/2+random(d)) % 252;
- if (c<0)
- c=-c;
- else
- if (!c)
- c=1;
- putpixel(x,y,abs(c));
- } /* end of adjust(x1,y1,x,y,x2,y2) */
-
- int getpixel(int x,int y)
- {return(peekb(0xa000,320*y+x) & 0xff);
- } /* end of int getpixel(x,y) */
-
- void putpixel(int x,int y,int c)
- {pokeb(0xa000,320*y+x,c);
- } /* end of putpixel(x,y,c) */
-
- void rotatepalette(colortype p[])
- {colortype temp;
- if (direction)
- {memmove(&temp,p+252,sizeof(colortype));
- memmove(p+2,p+1,251*sizeof(colortype));
- memmove(p+1,&temp,sizeof(colortype));
- }
- else
- {memmove(&temp,p+1,sizeof(colortype));
- memmove(p+1,p+2,251*sizeof(colortype));
- memmove(p+252,&temp,sizeof(colortype));
- }
- setvgapalette(p,0,128);
- setvgapalette(p+128,128,128);
- } /* end of rotatepalette(p) */
-
- void setvgapalette(void *buffer,int first,int length)
- {asm cli /* Disable interrupts. */
- asm mov dx,3dah
- setvgapalette1: /* Wait for vertical retrace to end. */
- asm in al,dx
- asm test al,8
- asm jnz setvgapalette1
- setvgapalette2: /* Wait for vertical retrace to start. */
- asm in al,dx
- asm test al,8
- asm jz setvgapalette2
- /* Set the VGA palette registers. */
- asm push ds
- _DS=FP_SEG(buffer);
- _SI=FP_OFF(buffer);
- asm mov dx,3c8h /* port address of DAC address register. */
- asm mov ax,first /* this is the number of first DAC register to update. */
- asm out dx,al /* start with this DAC. */
- asm inc dx /* 3c9h is the port address where the RGB info is written. */
- asm mov cx,length /* this is the number of DAC registers to update. */
- setdacloop:
- asm mov al,[si]
- asm out dx,al
- asm inc si
- asm mov al,[si]
- asm out dx,al
- asm inc si
- asm mov al,[si]
- asm out dx,al
- asm inc si
- asm loop setdacloop
- asm pop ds
- asm sti /* Enable interrupts. */
- } /* end of setvgapalette(buffer,first,length) */
-
- void subdivide(int x1,int y1,int x2,int y2)
- {int c,x,y;
- if (bioskey(1))
- return;
- if (x2-x1<2 && y2-y1<2)
- return;
- x=(x1+x2)/2;
- y=(y1+y2)/2;
- adjust(x1,y1,x,y1,x2,y1);
- adjust(x2,y1,x2,y,x2,y2);
- adjust(x1,y2,x,y2,x2,y2);
- adjust(x1,y1,x1,y,x1,y2);
- if (getpixel(x,y)==0)
- {c=(getpixel(x1,y1)+getpixel(x2,y1)+getpixel(x2,y2)+getpixel(x1,y2))/4;
- if (c<1)
- c=1;
- else
- if (c>252)
- c=252;
- putpixel(x,y,c);
- }
- subdivide(x1,y1,x,y);
- subdivide(x,y1,x2,y);
- subdivide(x,y,x2,y2);
- subdivide(x1,y,x,y2);
- } /* end of subdivide(x1,y1,x2,y2) */
-
- /* Use bisection to find the root of y=x*x-n.
- Return the value of x. */
- unsigned sqrt(long n)
- {long xl,x,xh,y;
- if (n<0)
- n=-n;
- xl=0L; /* (xl,xh) is the range of y=x*x-n */
- xh=46340L;
- while(xl<xh-1L)
- {x=(xl+xh)/2;
- y=x*x;
- if (y<n)
- xl=x;
- else
- xh=x;
- }
- if (n-xl*xl < xh*xh-n)
- return((int)xl);
- else
- return((int)xh);
- } /* end of unsigned sqrt(n) */
-
- #if defined(dotest)
-
- void test(void)
- {int x,y,c;
- long h,v;
- for(x=0;x<320;x++)
- for(y=0;y<200;y++)
- {h=(long)(160-x);
- v=(long)(199-y);
- c=sqrt(h*h+v*v) % 252 + 1;
- putpixel(x,y,c);
- }
- } /* end of test() */
-
- #endif
-
- void usage(void)
- {printf("OOZE version %s compiled %s\n\n"
- "usage: OOZE [filename]\n"
- "where filename is the name of a .OOZ file.\n\n"
- "If the file does not exist, it will be created.\n"
- "If it already exists, the image in it will be oozed.\n"
- "If the filename parameter is not given, a default\n"
- "filename of OOZE.OOZ is assumed.\n",VERSION,__DATE__);
- } /* end of usage() */
-